﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using VirtualHost.Models;

namespace VirtualHost.Services {
    /// <summary>
    /// Nginx配置文件解析
    /// </summary>
    public class NginxConfigService {

        private int startIndex = 0;
        private int endIndex = 0;
        private String FileConf { get; set; }
        public List<HostSiteEntity> HostSites { get; private set; }


        public NginxConfigService(String conf_file) {
            FileConf = conf_file;
        }
        #region 1.0 解析Nginx配置文件
        public List<HostSiteEntity> ParseConfigFile() {
            List<HostSiteEntity> list = new List<HostSiteEntity>();
            if (!File.Exists(FileConf)) {
                return list;
            }
            HostSiteEntity entity = new HostSiteEntity();
            String[] lines = File.ReadAllLines(FileConf);
            int rowIndex = 0;
            int hostIndex = 1;
            startIndex = 0;
            Regex regex = new Regex(@"^(\w+)\s+(\S+);$");
            foreach (String line in lines) {
                if (line.Trim().StartsWith("#------ server start ---------#")) {
                    startIndex = rowIndex;
                }
                if (line.Trim().StartsWith("#------ server End ---------#")) {
                    endIndex = rowIndex;
                }
                rowIndex++;
                if (startIndex == 0) {
                    continue;
                }
                if (line.Trim().StartsWith("#name")) {
                    HostSiteEntity server = new HostSiteEntity { Id = "server" };
                    server.StartIndex = rowIndex;
                    server.Id = hostIndex++.ToString();
                    entity = server;
                    // 处理指令
                    Match directiveMatch = regex.Match(line.Trim());
                    KeyValuePair<String, String> dic = ParseDirective(line);
                    entity.Name = dic.Value;
                    list.Add(server);
                }
                // 去除注释和空白行
                if (line.Trim().StartsWith("#") || string.IsNullOrWhiteSpace(line)) {
                    continue;
                }
                if (line.Trim().StartsWith("server_name")) {
                    // 处理指令
                    Match directiveMatch = regex.Match(line.Trim());
                    if (directiveMatch.Success) {
                        entity.Domain = directiveMatch.Groups[2].Value.Trim();
                    }
                } else if (line.Trim().StartsWith("server")) {
                    // 开始一个新的嵌套块
                    //HostSiteEntity server = new HostSiteEntity { Id = "server" };
                    //server.StartIndex = rowIndex;
                    //server.Id = rowIndex.ToString();
                    //entity = server;
                    //list.Add(server);
                } else if (line.Trim().StartsWith("listen")) {
                    // 处理指令
                    Match directiveMatch = regex.Match(line.Trim());
                    KeyValuePair<String, String> dic = ParseDirective(line);
                    String[] vals = dic.Value.Split(' ');
                    if (vals.Length == 2) {
                        entity.IsHttps = true;
                        entity.Port = vals[0];
                    } else {

                        entity.Port = dic.Value.Trim();
                    }


                } else if (line.Trim().StartsWith("access_log")) {
                    // 处理指令
                    KeyValuePair<String, String> dic = ParseDirective(line);
                    entity.Logs = String.Join(" ", dic.Value);
                } else if (line.Trim().StartsWith("ssl_certificate")) {
                    // 处理指令 
                    Match directiveMatch = regex.Match(line.Trim());
                    if (directiveMatch.Success) {
                        entity.Certificate = directiveMatch.Groups[2].Value.Trim();
                    }
                } else if (line.Trim().StartsWith("ssl_certificate_key")) {
                    // 处理指令
                    Match directiveMatch = regex.Match(line.Trim());
                    if (directiveMatch.Success) {
                        entity.CertificateKey = directiveMatch.Groups[2].Value.Trim();
                    }
                } else if (line.Trim().StartsWith("root")) {
                    // 处理指令
                    Match directiveMatch = regex.Match(line.Trim());
                    if (directiveMatch.Success) {
                        entity.Path = directiveMatch.Groups[2].Value.Trim();
                    }
                } else if (line.Trim().StartsWith("index")) {
                    // 处理指令
                    entity.EndIndex = rowIndex;
                    KeyValuePair<String, String> dic = ParseDirective(line);
                    entity.Home = String.Join(" ", dic.Value);
                } else {
                    Console.WriteLine(line);
                }
            }
            HostSites = list;
            return list;
        }
        #endregion

        #region 3.0 保存Nginx配置文件
        public void SaveConfigFile() {
            HostSiteEntity entity = new HostSiteEntity();
            List<String> lines = new List<string>(File.ReadAllLines(FileConf));
            int rowIndex = startIndex + 1;
            int lineCount = 0;
            //如果这行有值且指令不同需要插入
            // 插入时需要从文件结尾开始否则导致索引不对 
            lines.RemoveRange(rowIndex, endIndex - rowIndex);
            StringBuilder builder = new StringBuilder();
            foreach (HostSiteEntity item in HostSites) {
                int index = item.EndIndex;
                String block = CreateBlock(item);
                lineCount += block.Count(t => t == '\n');
                lineCount++;
                builder.Append(block);
            }
            lines.Insert(rowIndex, builder.ToString());
            endIndex = startIndex + lineCount;
            //String contents = String.Join("\r\n", lines);
            File.WriteAllLines(FileConf, lines);
        }
        #endregion

        #region 1.0 解析一行指令 +KeyValuePair<String, String> ParseDirective(String line)
        /// <summary>
        /// 解析一行指令
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public KeyValuePair<String, String> ParseDirective(String line) {
            // 处理指令 
            line = line.Trim();
            if (line.EndsWith(";")) {
                line = line.Remove(line.Length - 1, 1);//去掉分号
            }
            String[] vals = line.Trim().Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            var keys = new List<String>(vals);
            keys.RemoveAt(0);
            String value = String.Join(" ", keys);
            return new KeyValuePair<String, String>(vals[0], value);
        }
        #endregion

        #region 2.0 创建一个Server块 +String CreateBlock(HostSiteEntity  entity) 
        /// <summary>
        /// 创建一个Server块
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public String CreateBlock(HostSiteEntity entity) {
            StringBuilder builder = new StringBuilder();
            builder.AppendFormat("  # HTTP{0} server\r\n", entity.IsHttps ? "S" : "");
            builder.AppendFormat("  #name {0}\r\n", entity.Name);
            builder.AppendLine("  server {");
            builder.AppendFormat("    listen       {0}{1};\r\n", entity.Port, entity.IsHttps ? " ssl" : "");
            builder.AppendFormat("    server_name  {0};\r\n", entity.Domain);
            builder.AppendFormat("    access_log  {0};\r\n", entity.Logs);
            if (entity.IsHttps) {
                builder.AppendFormat("    ssl_certificate      {0};\r\n", entity.Certificate);
                builder.AppendFormat("    ssl_certificate_key  {0};\r\n", entity.CertificateKey);
                builder.AppendLine("");
                builder.AppendFormat("    ssl_session_cache    shared:SSL:1m;\r\n");
                builder.AppendFormat("    ssl_session_timeout  5m;\r\n");
                builder.AppendLine("");
                builder.AppendFormat("    ssl_ciphers  HIGH:!aNULL:!MD5;\r\n");
                builder.AppendFormat("    ssl_prefer_server_ciphers  on;\r\n");
            }
            builder.AppendLine("");
            builder.AppendLine("    location / {");
            builder.AppendFormat("        root   {0};\r\n", entity.Path);
            builder.AppendFormat("        index  {0};\r\n", entity.Home);
            builder.AppendLine("    }");
            builder.AppendLine("  }");
            return builder.ToString();
        }
        #endregion

    }
}
